<template>
  <div>
    <div>算法</div>
    <div>图标识别</div>

    <div class="canvas1"></div>
    <button id="load-data" @click="predict">绘制Model Predictions vs Original Data</button>
    <button id="load-data" @click="singleTestModel">Load Data</button>
    <button id="load-data" @click="save">保存</button>
    <button id="load-data" @click="load">加载模型</button>
    <button id="start-training-1" disabled>Start Training</button>
  </div>
</template>

<script>
// import tfvis from '@tensorflow/tfjs-vis'
import * as tf from "@tensorflow/tfjs";
import * as tfvis from "@tensorflow/tfjs-vis";
import { loadGraphModel } from "@tensorflow/tfjs-converter";
export default {
  name: "ai_",
  data() {
    return {
      data: null,
      examples: null,
      model: null,
      tensorData: null,
      predictData: null,
    };
  },
  methods: {
    // 预测
    predict() {
      this.$nextTick(() => {
        this.testModel(this.model, this.data, this.tensorData);
      });
    },

    // 绘图示例，可以去 @tensorflow/tfjs-vis 里面看类型去
    async runExample() {
      // Load and plot the original input data that we are going to train on.
      //   const data = await this.getData();
      //   var values = data.map((d) => ({
      //     x: d.horsepower,
      //     y: d.mpg,
      //   }));
      //   console.log(values, "values");
      // 散点图
      var values = [
        {
          x: 20,
          y: 20,
        },
        {
          x: 165,
          y: 30,
        },
        {
          x: 165,
          y: 30,
        },
        {
          x: 165,
          y: 30,
        },
      ];

      //   tfvis.render.scatterplot(
      //     { name: "Horsepower v MPG" },
      //     { values },
      //     {
      //       xLabel: "x轴的坐标",
      //       yLabel: "y轴的坐标",
      //       height: 300,
      //     }
      //   );

      //柱状图
      //   const data = [
      //     { index: 0, value: 50 },
      //     { index: 1, value: 100 },
      //     { index: 2, value: 150 },
      //   ];
      //   const surface = { name: "Bar chart", tab: "Charts" };
      //   tfvis.render.barchart(surface, data);

      //混淆矩阵
      //   const data = {
      //     values: [
      //       [4, 2, 8],
      //       [1, 7, 2],
      //       [3, 3, 20],
      //     ],
      //   };
      //   // Render to visor
      //   const surface = {
      //     name: "Confusion Matrix with Excluded Diagonal",
      //     tab: "Charts",
      //   };
      //   tfvis.render.confusionMatrix(surface, data, {
      //     shadeDiagonal: false,
      //   });

      //折线图
      const series1 = Array(100)
        .fill(0)
        .map((y) => Math.random() * 100 + 50)
        .map((y, x) => ({ x, y }));
      const data = { values: [series1] };

      // Render to visor
      const surface = { name: "Zoomed Line Chart", tab: "Charts" };
      tfvis.render.linechart(surface, data, { zoomToFit: true });
    },
    async run() {
      //   Load and plot the original input data that we are going to train on.
      //   const data = await this.getData();
      //   var values = data.map((d) => ({
      //     x: d.horsepower,
      //     y: d.mpg,
      //   }));

      //   tfvis.render.scatterplot(
      //     { name: "Horsepower v MPG" },
      //     { values },
      //     {
      //       xLabel: "x轴的坐标",
      //       yLabel: "y轴的坐标",
      //       height: 300,
      //     }
      //   );

      // 主要在这里创造model
      this.createModel();
      // Prepare the model for training.
      // Convert the data to a form we can use for training.
      const tensorData = this.dataPre();
      const { inputs, labels } = tensorData;
      this.tensorData = tensorData;
      // Train the model
      this.trainModel(this.model, inputs, labels);
      console.log("Done Training");

      var that = this;
    },
    createModel() {
      // Create a sequential model
      this.model = tf.sequential();
      // Add a single hidden layer 添加图层
      //   model.add(tf.layers.dense({units: 50, activation: 'sigmoid'})); 在这种情况下是sigmoid激活
      this.model.add(tf.layers.dense({ inputShape: [1], units: 1, useBias: true }));
      // Add an output layer
      this.model.add(tf.layers.dense({ units: 1, useBias: true }));
      return this.model;
    },
    //数据预处理
    dataPre() {
      //   tf.util.shuffle(this.data);
      // 转换为张量 这里我们制作两个数组，一个用于我们的输入示例（马力条目），另一个用于真正的输出值（在机器学习中称为标签）。
      console.log(this.data, "预期训练的模型");
      this.data = [
        {
          x: 201,
          y: 1,
        },
        {
          x: 1,
          y: 0,
        },
        {
          x: [[2, 1]],
          y: 1,
        },
        {
          x: [[1, 1]],
          y: 1,
        },
      ];

      //   var inputs = this.data.map((d) => d.horsepower);
      //   const labels = this.data.map((d) => d.mpg);
      var inputs = this.data.map((d) => d.x);
      const labels = this.data.map((d) => d.y);
      const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
      const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
      // 规范化数据 -1 - 1
      var inputMax = inputTensor.max();
      const inputMin = inputTensor.min();
      const labelMax = labelTensor.max();
      const labelMin = labelTensor.min();
      const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
      const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));
      this.predictData = {
        inputMin: inputMin,
        inputMax: inputMax,
        labelMax: labelMax,
        labelMin: labelMin,
      };
      return { inputs: normalizedInputs, labels: normalizedLabels };
    },

    //训练模型
    async trainModel(model, inputs, labels) {
      this.model.compile({
        optimizer: tf.train.adam(),
        loss: tf.losses.meanSquaredError,
        metrics: ["mse"],
      });
      const batchSize = 28;
      const epochs = 50;
      return await this.model.fit(inputs, labels, {
        batchSize,
        epochs,
        shuffle: true,
        //这里展示图像
        callbacks: tfvis.show.fitCallbacks(
          { name: "Training Performance" },
          ["loss", "mse"],
          { height: 200, callbacks: ["onEpochEnd"] }
        ),
      });
    },
    //预测
    testModel(model, inputData, normalizationData) {
      const { inputMax, inputMin, labelMin, labelMax } = this.predictData;
      console.log(inputMax, inputMin, labelMin, labelMax, normalizationData);
      // Generate predictions for a uniform range of numbers between 0 and 1;
      // We un-normalize the data by doing the inverse of the min-max scaling
      // that we did earlier.
      const [xs, preds] = tf.tidy(() => {
        const xs = tf.linspace(0, 1, 100);
        const preds = model.predict(xs.reshape([100, 1]));

        const unNormXs = xs.mul(inputMax.sub(inputMin)).add(inputMin);

        const unNormPreds = preds.mul(labelMax.sub(labelMin)).add(labelMin);

        // Un-normalize the data
        return [unNormXs.dataSync(), unNormPreds.dataSync()];
      });

      const predictedPoints = Array.from(xs).map((val, i) => {
        return { x: val, y: preds[i] };
      });

      const originalPoints = inputData.map((d) => ({
        x: d.horsepower,
        y: d.mpg,
      }));

      tfvis.render.scatterplot(
        { name: "Model Predictions vs Original Data" },
        { values: [originalPoints, predictedPoints], series: ["original", "predicted"] },
        {
          xLabel: "Horsepower",
          yLabel: "MPG",
          height: 300,
        }
      );
    },
    singleTestModel() {
      var inputs = [300];
      const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
      alert(this.model.predict(inputTensor.reshape([1, 1])));
    },
    async save() {
      //本地存储空间（仅限浏览器）
      await this.model.save("localstorage://my-model-1");
      //    await this.model.save('downloads://my-model');
      alert("保存模型成功");
    },
    async load() {
      //本地存储空间（仅限浏览器）tensorflowjs_models/my-model-1/model_topology
      const MODEL_URL = "localstorage://my-model-1";
      var inputs = [300];
      const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
      //加载预测模型
      const model = await tf.loadLayersModel("localstorage://my-model-1");
      //加载图形分析模型
      // const model = await loadGraphModel(MODEL_URL);
      alert(model.predict(inputTensor.reshape([1, 1])));
    },
  },
  mounted() {
    //   这里是示例
    document.addEventListener("DOMContentLoaded", this.run());
  },
};
</script>

<style lang="scss" scoped></style>
